/*
 * Copyright 2008 Neil Bacon
 * Distributed under the terms of the Mozilla Public License version 1.1
 * or the GNU General Public License version 3.
 */

package nb.util;

import nb.xadd.XADDRuntimeException;

public class Utils {

//    private static final Log log = LogFactory.getLog(Utils.class);
    
    private static final String indent = "  ";

    /** Only static methods. */
    private Utils() {
    }

    /**
     * Append depth*2 spaces to buf.
     * @param depth indent level
     * @param buf text buffer
     */
    public static void appendIndent(int depth, StringBuilder buf) {
        for (int i = 0; i < depth; i++) {
            buf.append(indent);
        }
    }

    /**
     * HashCode of a double.
     * @see {@link Double#hashCode()}
     * @return hashCode
     */
    public static int hashCode(double value) {
        long v = Double.doubleToLongBits(value);
        return (int)(v^(v>>>32));
    }

    /**
     * HashCode of a boolean.
     * @see {@link Boolean#hashCode()}
     * @return hashCode
     */
    public static int hashCode(boolean value) {
        return value ? 1231 : 1237;
    }

    /**
     * @return nearest multiple of resolution to x;
     */
    public static double round(double x, double resolution) {
//        if (log.isDebugEnabled()) {
//            log.debug("round: floor = " + Math.floor((x + resolution/2.0) /resolution));
//        }
        return Math.floor((x + resolution/2.0) /resolution) * resolution;
    }

    /**
     * @return copy of values with each element rounded as above.
     */
    public static double[] round(double[] values, double resolution) {
        double[] x = new double[values.length];
        for (int i = 0; i < x.length; i++) {
            x[i] = round(values[i], resolution);
        }
        return x;
    }

    /**
     * Reversible mapping from pairs of ints to an int.
     * £((m, n)) := m + (m+n-2)(m+n-1)/2 ;
     * @see {@link http://www.cs.berkeley.edu/~wkahan/Math55/pairs.pdf}
     * We add one to both m and n because this paper deals with
     * m, n > 0, but we need m, n >= 0.
     * @param m >= 0
     * @param n >= 0
     * @return
     */
    public static int pairToInt(int m, int n) {
        int k = m + 1 + (m+n)*(m+n+1)/2;
        // log.debug("pairToInt: " + m + ", " + n + " -> " + k);
        return k;
    }

    /**
     * Inverse of {@link #pairToInt(int, int)} mapping.
     * L(k) := integer part of ( 1/2 + √(2k - 1) ) ;
     * M(k) := k - ( L(k) - 1 )L(k)/2 ;
     * P(k) := ( M(k), 1+L(k)-M(k) ).
     * We subtract one from the resulting pair for m, n >= 0.
     * @param k
     * @param pair
     */
    public static void intToPair(int k, int[] pair, int pairOffset) {
        int l = (int) (Math.sqrt(2 * k - 1) + 0.5);
        int m = k - (l-1)*l/2;
        pair[pairOffset]   = m - 1;
        pair[pairOffset+1] = l - m;
        // log.debug("intToPair: " + k + " -> " + pair[pairOffset] + ", " + pair[pairOffset+1]);
    }

    /**
     * Reversible mapping from array of ints to an int.
     * @param index
     * @return unique int key corresponding to index[]
     */
    public static int indexToKey(int[] index) {
        int key = index[0];
        int prev = key;
        for (int i = 1; i < index.length; i++) {
            if (index[i] < prev) {
                throw new XADDRuntimeException("index[" + i + "] = " + index[i] + " < index[" + (i-1) + "] = " + prev);
            }
            key = Utils.pairToInt(key, prev = index[i]);
        }
        // log.debug("indexToKey: " + Arrays.toString(index) + " -> " + key);
        return key;
    }

    /**
     * Inverse of {@link #indexToKey(int[])} mapping.
     * @param key
     * @param index index[] is set to unique values corresponding to key
     */
    public static void keyToIndex(int key, int[] index) {
        if (index.length == 1) {
            index[0] = key;
        } else {
            int k = key;
            for (int i = index.length - 2; i >= 0; --i) {
                intToPair(k, index, i);
                k = index[i];
            }
        }
        // log.debug("keyToIndex: " + key + " -> " + Arrays.toString(index));
    }
}
